#include "rs232_handler.h"
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <pthread.h>
#include <stdatomic.h>
#include <sys/epoll.h>
#include <sys/syscall.h>

#define UART1 "/dev/ttyS1"
#define DEFAULT_SPEED 9600
#define DEFAULT_BITS 8
#define DEFAULT_EVENT 'N'
#define DEFAULT_STOP 1
#ifndef MAX_EVENTS
#define MAX_EVENTS 128
#endif

struct rs232_object {
    int32_t fd;
    int32_t nByte;
    uint8_t buffer[512];
};

struct epoll_object {
    int     epoll_fd;
    struct  epoll_event  event;
    struct  epoll_event  event_array[MAX_EVENTS];
    int     events;
};

typedef struct _rs232_handler{
    atomic_int is_inited;
    atomic_int is_exit;
    pthread_t  recv_thread;
    struct rs232_object rs232_module;
    struct epoll_object epoll_module;
    recv_data_cb_t m_cb;
}rs232_handler;

int set_opt(int fd, int nSpeed, int nBits, char nEvent, int nStop);
void* recv_func(void* args);

rs232_handler* rs232_get_instance() {
    static rs232_handler handler;
    return &handler;
}

int rs232_module_init() {
    rs232_handler* handler = rs232_get_instance();
    if(atomic_load(&handler->is_inited)) return -1;
    atomic_store(&handler->is_exit, 0);
    handler->m_cb = NULL;
    memset(handler->rs232_module.buffer, 0, sizeof(handler->rs232_module.buffer));
    if ((handler->rs232_module.fd = open(UART1, O_RDWR | O_NONBLOCK)) < 0) { //非阻塞读方式
		fprintf(stderr, "open %s is failed", UART1);
        return -2;
    }

    set_opt(handler->rs232_module.fd, DEFAULT_SPEED, DEFAULT_BITS, DEFAULT_EVENT, DEFAULT_STOP);
    handler->epoll_module.epoll_fd = epoll_create1(EPOLL_CLOEXEC);
    if(handler->epoll_module.epoll_fd <= 0) {
        close(handler->rs232_module.fd);
        handler->rs232_module.fd = -1;
        return -3;
    }

    handler->epoll_module.event.events = EPOLLIN;
    handler->epoll_module.event.data.fd = handler->rs232_module.fd;

    if(epoll_ctl(handler->epoll_module.epoll_fd, EPOLL_CTL_ADD, handler->rs232_module.fd, &handler->epoll_module.event) < 0) {
        if(handler->epoll_module.epoll_fd > 0) {
            close(handler->epoll_module.epoll_fd);
            handler->epoll_module.epoll_fd = -1;
        }
        if(handler->rs232_module.fd > 0) {
            close(handler->rs232_module.fd);
            handler->rs232_module.fd = -1;
        }
        return -4;
    }
    pthread_create(&handler->recv_thread, NULL, recv_func, NULL);

    fprintf(stderr, "%s done\n", __func__);
    atomic_store(&handler->is_inited, 1);
    return 0;
}

int rs232_module_deinit() {
    rs232_handler* handler = rs232_get_instance();
    if(!atomic_load(&handler->is_inited)) return -1;
    atomic_store(&handler->is_exit, 1);
    pthread_join(handler->recv_thread, NULL);
    if(handler->epoll_module.epoll_fd > 0) {
        close(handler->epoll_module.epoll_fd);
        handler->epoll_module.epoll_fd = -1;
    }
    if(handler->rs232_module.fd > 0) {
        close(handler->rs232_module.fd);
        handler->rs232_module.fd = -1;
    }
    atomic_store(&handler->is_inited, 0);
    return 0;
}

int rs232_rs232_module_write(const char* string, const uint32_t length) {
    rs232_handler* handler = rs232_get_instance();
    if(!atomic_load(&handler->is_inited) || NULL == string || 0 == length) return -1;
    return write(handler->rs232_module.fd, string, length);
}

void rs232_module_set_recv_cb(recv_data_cb_t cb) {
    rs232_handler* handler = rs232_get_instance();
    handler->m_cb = cb;
}

int set_opt(int fd, int nSpeed, int nBits, char nEvent, int nStop)
{
	struct termios newtio, oldtio;
	if (tcgetattr(fd, &oldtio) != 0)
	{
		perror("SetupSerial 1");
		return -1;
	}
	bzero(&newtio, sizeof(newtio));
	newtio.c_cflag |= CLOCAL | CREAD;
	newtio.c_cflag &= ~CSIZE;

	switch (nBits)
	{
	case 7:
		newtio.c_cflag |= CS7;
		break;
	case 8:
		newtio.c_cflag |= CS8;
		break;
	}

	switch (nEvent)
	{
	case 'O':
		newtio.c_cflag |= PARENB;
		newtio.c_cflag |= PARODD;
		newtio.c_iflag |= (INPCK | ISTRIP);
		break;
	case 'E':
		newtio.c_iflag |= (INPCK | ISTRIP);
		newtio.c_cflag |= PARENB;
		newtio.c_cflag &= ~PARODD;
		break;
	case 'N':
		newtio.c_cflag &= ~PARENB;
		break;
	}

	switch (nSpeed)
	{
	case 2400:
		cfsetispeed(&newtio, B2400);
		cfsetospeed(&newtio, B2400);
		break;
	case 4800:
		cfsetispeed(&newtio, B4800);
		cfsetospeed(&newtio, B4800);
		break;
	case 9600:
		cfsetispeed(&newtio, B9600);
		cfsetospeed(&newtio, B9600);
		break;
	case 115200:
		cfsetispeed(&newtio, B115200);
		cfsetospeed(&newtio, B115200);
		break;
	case 460800:
		cfsetispeed(&newtio, B460800);
		cfsetospeed(&newtio, B460800);
		break;
	default:
		cfsetispeed(&newtio, B9600);
		cfsetospeed(&newtio, B9600);
		break;
	}
	if (nStop == 1)
		newtio.c_cflag &= ~CSTOPB;
	else if (nStop == 2)
		newtio.c_cflag |= CSTOPB;
	newtio.c_cc[VTIME] = 100; ///* 设置超时10 seconds*/
	newtio.c_cc[VMIN] = 0;
	tcflush(fd, TCIFLUSH);
	if ((tcsetattr(fd, TCSANOW, &newtio)) != 0)
	{
		perror("com set error");
		return -1;
	}

	//	printf("set done!\n\r");
	return 0;
}

void* recv_func(void* args) {
    rs232_handler* handler = rs232_get_instance();
    fprintf(stderr, "%s current thread id is %d\n", __func__, syscall(SYS_gettid));
    while (!atomic_load(&handler->is_exit)) {
        handler->epoll_module.events = epoll_wait(handler->epoll_module.epoll_fd, handler->epoll_module.event_array, MAX_EVENTS, 1000);
        if(atomic_load(&handler->is_exit)) break;

        if(0 > handler->epoll_module.events) {
            fprintf(stderr, "1 epoll failure: %s\n", strerror(errno));
            break;
        }else if(0 == handler->epoll_module.events) {
            // fprintf(stderr, "---------------epoll timeout\n");
            usleep(10000);
            continue;
        }

        for(int index = 0; index < handler->epoll_module.events; index++) {
            if((handler->epoll_module.event_array[index].events&EPOLLERR) || (handler->epoll_module.event_array[index].events&EPOLLHUP)) {
                fprintf(stderr, "epoll_wait get error on fd[%d]: %s\n", handler->epoll_module.event_array[index].data.fd, strerror(errno));
                //将event_array[i].data.fd从epollfd中删除；
                epoll_ctl(handler->epoll_module.epoll_fd, EPOLL_CTL_DEL, handler->epoll_module.event_array[index].data.fd, NULL);
                close(handler->epoll_module.event_array[index].data.fd);
                continue;
            }
            /*处理当前事件*/
            if(handler->epoll_module.event_array[index].data.fd == handler->rs232_module.fd) {
                fprintf(stderr, "epoll_wait get fd %d\n", handler->rs232_module.fd);
                memset(handler->rs232_module.buffer, 0, sizeof(handler->rs232_module.buffer));
                handler->rs232_module.nByte = read(handler->rs232_module.fd, handler->rs232_module.buffer, 512);
                if(handler->rs232_module.nByte > 0 && NULL != handler->m_cb) {
                    handler->m_cb(handler->rs232_module.buffer, handler->rs232_module.nByte);
                }
            }else {
                /*处理其他事件*/
                fprintf(stderr, "epoll_wait get extra fd %d\n", handler->epoll_module.event_array[index].data.fd);
            }
        }
    }
    return NULL;
}